feat(reference): replace the humanizer dependency with /prose-editing - #89
Merged
Conversation
Ship a generic technical-prose rewrite skill that STE-flavors a draft and proves it with a stdlib linter, as a sibling to /humanizer. Co-authored-by: Cursor <cursoragent@cursor.com>
The skill should state the rewrite loop, not the kits that inspired it. Co-authored-by: Cursor <cursoragent@cursor.com>
A git hook exports GIT_DIR, GIT_WORK_TREE and friends. Any `git` the test suite runs while those are set operates on the hook's repository rather than the temporary directory the test asked for: `git init` rewrites that repository's config and marks a normal checkout core.bare=true, and the `git add` that follows targets the real index. Both call sites were exposed. The one in tests/conftest.py is the worse of the two because it is a shared fixture that runs init, add, and commit. Add git_env() to tests/conftest.py, which returns the environment minus the variables git uses to locate a repository, and route both call sites through it. Identity variables such as GIT_AUTHOR_NAME are kept because they do not redirect anything. The regression test stands where a hook stands, with GIT_DIR pointing at another repository, and asserts git init both lands where it was told to and leaves that other repository alone.
The pre-commit pytest hook runs with GIT_DIR set, so the unprotected git init in the test suite retargets the checkout it is running in, marks it core.bare=true, and fails. This branch cannot run its own hooks without that fix, so it builds on it. # Conflicts: # tests/unit/test_release_cli.py
Two skills carried the external /humanizer as a hard prerequisite while a separate proposal added a Simplified Technical English skill beside it. Measuring them showed they were not complements. A sample holding seventeen distinct AI writing tells scored 5.93 against the STE linter's 2.5 bar, and every flagged category was incidental: four contractions, passive voice, a nominalization, a long paragraph. None of the seventeen tells was detected. An agent repairing what the linter reported would return prose that was still obviously machine-written, carrying a passing score. Merge them into one model-invoked reference skill, /prose-editing, with a human-invoked wrapper, /clean-prose, and remove the external dependency. The two systems do not disagree about tells, they disagree about compression. That gives three layers: mechanical tells scored in every register, compression scored only where prose should be flat, voice scored only where prose is allowed one. Registers are strict, flavored and voiced, inferred from document type, plus a read-only review route. Ambiguity resolves toward the register that changes least, so a CVE changelog keeps "may allow remote code execution". A caller that knows names its register: rhdh-pr-review uses flavored, rhdh-release-announce uses voiced. The score is a delta rather than a gate. A fixed bar rejected prose this repository already treats as good, so the skill reports before and after and the bar survives only as --fail-over for a corpus a human owns. Prose is restated rather than copied. The upstream catalogue derives from Wikipedia's CC BY-SA "Signs of AI writing", which Apache-2.0 cannot absorb, so the taxonomy is taken and every rule written here. scripts/NOTICE carries the MIT terms of both upstream projects. The catalog validator learns the delegating wrapper: a body of one short line naming exactly one model-invoked skill owes no Completion section, and is checked instead for a delegate that exists and can be reached. Named-invocation checking no longer assumes an rhdh- prefix, so renaming a generically named skill can no longer leave its callers dangling.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the external
/humanizerdependency with an in-pack reference skill,/prose-editing, plus a human-invoked wrapper,/clean-prose. Recorded inADR-0010.
This started as "add an STE skill beside humanizer". Measuring the two together
showed they were not complements. A sample holding seventeen distinct AI writing
tells scored 5.93 against the STE linter's 2.5 bar — so it failed — but every
flagged category was incidental: four contractions, passive voice, a
nominalization, a long paragraph. Not one of the seventeen tells was detected.
An agent repairing what the linter reported would have returned prose that was
still obviously machine-written, carrying a passing score. Two skills also
claimed the same utterances, which ADR-0005 forbids.
The design
STE and humanizer do not disagree about tells. They disagree about
compression. That gives three layers and four routes:
strictflavoredvoicedreviewMechanical tells score in every register. The register is inferred from document
type, never asked, and ambiguity resolves toward the register that changes
least — so a CVE changelog keeps
may allow remote code execution. A callerthat knows names its own:
/rhdh-pr-reviewusesflavored,/rhdh-release-announceusesvoiced.The score is a delta, not a gate. A fixed bar rejected prose this repository
already treats as good, so the skill reports before and after. The bar survives
only as
--fail-over Nfor a corpus a human owns.Licensing
The upstream catalogue derives from Wikipedia's CC BY-SA Signs of AI writing,
which an Apache-2.0 repository cannot absorb. The taxonomy is taken and every
rule restated here; a 7-gram overlap scan against both sources confirms the only
remaining matches are watched-phrase list entries, which are data.
skills/reference/prose-editing/scripts/NOTICEcarries the full MIT terms ofboth upstream projects.
Also in this PR
A git bug that corrupts the developer's checkout. The pre-commit hook exports
GIT_DIR, so the unprotectedgit initin the test suite retargeted the realrepository, marked it
core.bare=true, and pointed the followinggit add .atthe real index. Both call sites were exposed;
tests/conftest.pywas the worseone because it is a shared fixture that runs init, add, and commit. Fixed with a
git_env()helper and a regression test that stands where a hook stands.Two validator gaps. A skill with no
##headings could escape the## Completionrequirement entirely; the delegating-wrapper shape is now narrowenough that a real skill cannot fall into it, and it is checked instead for a
delegate that exists and is model-invoked. Separately, named-invocation checking
assumed an
rhdh-prefix, so renaming a generically named skill(
prose-editing,mutation-gate,skill-authoring) left its callers danglingsilently.
Test plan
uv run pytest— 446 passed, 6 skippeduv run python scripts/validate_skill_catalog.py --json— valid, 43 skills, 3 human-invokedpython skills/reference/prose-editing/scripts/lint.py --helplists--register,--quote-safe,--baseline,--fail-overreferences/scores the category it teaches (pinned bytest_every_documented_example_scores_the_category_it_teaches)/rhdh-pr-reviewand/rhdh-release-announcename their registers and no longer reference/humanizerKnown limitations
Worth knowing before setting bars: on this corpus
em_dashandlong_sentenceare 50.7% of all violations, while everything a reader would call an AI tell
totals 18 of 3304 (0.5%). That is largely because the repository's prose is
human-written and genuinely clean — but it means
over_barcurrently reportsem-dash and sentence-length density. Bars are left at 1.5 / 2.5 / 2.0 for a human
to calibrate.
title_case_headingnow requires a capitalized minor word as evidence, whichdrops it from 368 corpus hits to 2. A proper-noun lexicon cannot cover a product
namespace without decapitalizing
Red Hat Advanced Cluster Security. Headingcase belongs in markdownlint rather than in a slop score.